import tkinter as tk
from tkinter import ttk, messagebox, simpledialog, scrolledtext
import socket
import threading
import os
import hashlib
from datetime import datetime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import getpass
import sys


class VotingRound:
    def __init__(self, name, vote_mode, mode_value, vote_type, password=None):
        self.name = name

        # 将中文模式转换为英文关键字
        if vote_mode == '最大':
            self.vote_mode = 'max'
        elif vote_mode == '固定':
            self.vote_mode = 'fixed'
        else:
            self.vote_mode = vote_mode

        self.mode_value = mode_value
        self.vote_type = vote_type
        self.password_hash = hashlib.sha256(password.encode()).hexdigest() if password else None
        self.candidates = {}
        self.voters = {}
        self.invalid_votes = []
        self.status = "active"
        self.start_time = datetime.now()

    def add_candidate(self, name):
        cid = len(self.candidates) + 1
        self.candidates[cid] = [name, 0]
        return cid

    def validate_vote(self, user_id, candidate_ids):
        if self.vote_type == '记名' and user_id in self.voters:
            return False, "不能重复投票"

        num_votes = len(candidate_ids)
        if self.vote_mode == 'max' and num_votes > self.mode_value:
            return False, f"最多选{self.mode_value}人"
        if self.vote_mode == 'fixed' and num_votes != self.mode_value:
            return False, f"必须选{self.mode_value}人"
        if any(cid not in self.candidates for cid in candidate_ids):
            return False, "无效候选人ID"

        return True, "投票有效"

    def process_vote(self, user_id, candidate_ids):
        is_valid, reason = self.validate_vote(user_id, candidate_ids)
        if not is_valid:
            self.invalid_votes.append((user_id, reason))
            return f"无效票: {reason}"

        for cid in candidate_ids:
            self.candidates[cid][1] += 1

        if self.vote_type == '记名':
            self.voters[user_id] = candidate_ids

        return "投票成功"

    def get_summary(self):
        summary = [f"=== {self.name} 投票结果 ==="]
        for cid, (name, votes) in self.candidates.items():
            summary.append(f"{cid}. {name}: {votes}票")
        return "\n".join(summary)

    def get_candidates_info(self):
        info = [f"=== {self.name} 候选人 ==="]
        for cid, (name, _) in self.candidates.items():
            info.append(f"{cid}. {name}")
        return "\n".join(info)

    def save_to_file(self):
        filename = f"{self.name}_结果_{datetime.now().strftime('%Y%m%d%H%M%S')}.txt"
        with open(filename, 'w') as f:
            f.write(self.get_summary())
        return f"结果已保存到: {filename}"

    def get_voter_info(self, password):
        if self.vote_type != '记名':
            return "无记名投票，无法查看"

        if not self.password_hash or hashlib.sha256(password.encode()).hexdigest() != self.password_hash:
            return "密码错误"

        info = [f"=== {self.name} 投票详情 ==="]
        info.append(f"投票模式: {'最多选' if self.vote_mode == 'max' else '必须选'} {self.mode_value} 人")
        info.append(f"总投票人数: {len(self.voters)}")
        info.append("")

        for user_id, cids in self.voters.items():
            candidate_names = []
            for cid in cids:
                candidate_names.append(f"候选人{cid}({self.candidates[cid][0]})")
            info.append(f"用户 {user_id}: 投给 {', '.join(candidate_names)}")
        return "\n".join(info)

    def save_voter_info(self, password):
        info = self.get_voter_info(password)
        if "密码错误" in info or "无记名投票" in info:
            return info

        filename = f"{self.name}_投票详情_{datetime.now().strftime('%Y%m%d%H%M%S')}.txt"
        with open(filename, 'w') as f:
            f.write(info)
        return f"详情已保存到: {filename}"


class VotingSystem:
    def __init__(self):
        self.rounds = {}
        self.current_round_id = None

    def create_round(self, name, vote_mode, mode_value, vote_type, password=None):
        round_id = len(self.rounds) + 1
        self.rounds[round_id] = VotingRound(name, vote_mode, mode_value, vote_type, password)
        self.current_round_id = round_id
        return round_id

    def get_current_round(self):
        if self.current_round_id in self.rounds:
            return self.rounds[self.current_round_id]
        return None

    def end_round(self, round_id):
        if round_id in self.rounds:
            self.rounds[round_id].status = "closed"
            return self.rounds[round_id].save_to_file()
        return "轮次不存在"


def encrypt(message, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return iv + cipher.encrypt(pad(message.encode(), AES.block_size))


def decrypt(data, key):
    try:
        iv, encrypted = data[:16], data[16:]
        cipher = AES.new(key, AES.MODE_CBC, iv)
        return unpad(cipher.decrypt(encrypted), AES.block_size).decode()
    except Exception:
        return "解密错误"


def handle_client(client_socket, system, log_callback):
    key = os.urandom(16)
    iv = os.urandom(16)
    client_socket.sendall(key + iv)

    client_address = client_socket.getpeername()
    log_callback(f"客户端 {client_address} 已连接")

    try:
        current_round = system.get_current_round()
        if not current_round:
            client_socket.sendall(encrypt("无活动轮次", key, iv))
            log_callback("无活动轮次，拒绝客户端请求")
            return

        # 发送候选人信息
        candidates_info = current_round.get_candidates_info()
        client_socket.sendall(encrypt(candidates_info, key, iv))
        log_callback(f"向客户端 {client_address} 发送候选人信息")

        # 创建投票规则信息
        if current_round.vote_mode == 'max':
            rule_info = f"投票类型: {current_round.vote_type}, 最多可选 {current_round.mode_value} 位候选人"
        elif current_round.vote_mode == 'fixed':
            rule_info = f"投票类型: {current_round.vote_type}, 必须选择 {current_round.mode_value} 位候选人"
        else:
            rule_info = f"投票类型: {current_round.vote_type}, 投票模式: {current_round.vote_mode}"

        client_socket.sendall(encrypt(rule_info, key, iv))
        log_callback(f"向客户端 {client_address} 发送投票规则")

        while True:
            data = client_socket.recv(1024)
            if not data:
                log_callback(f"客户端 {client_address} 断开连接")
                break

            try:
                decrypted = decrypt(data, key)
                log_callback(f"收到来自 {client_address} 的数据: {decrypted}")

                if decrypted.startswith("VOTE|"):
                    try:
                        # 分割命令格式：VOTE|user_id|cid1,cid2,...
                        parts = decrypted.split('|', 2)  # 最多分割2次，得到3部分

                        if len(parts) < 3:
                            raise ValueError("命令格式不完整")

                        _, user_id, cids_str = parts

                        # 验证用户ID
                        user_id = user_id.strip()
                        if not user_id:
                            raise ValueError("用户ID不能为空")

                        # 转换候选人ID
                        candidate_ids = []
                        for cid in cids_str.split(','):
                            cid = cid.strip()
                            if cid:  # 忽略空值
                                candidate_ids.append(int(cid))

                        if not candidate_ids:
                            raise ValueError("候选人ID不能为空")

                        # 处理投票
                        response = current_round.process_vote(user_id, candidate_ids)
                        client_socket.sendall(encrypt(response, key, iv))
                        log_callback(f"处理投票: 用户 {user_id} 投给候选人 {cids_str} - {response}")

                    except Exception as e:
                        error_msg = f"命令格式错误: {str(e)}"
                        client_socket.sendall(encrypt(error_msg, key, iv))
                        log_callback(f"处理投票错误: {error_msg}")

                else:
                    client_socket.sendall(encrypt("未知命令", key, iv))
                    log_callback(f"未知命令: {decrypted}")

            except Exception as e:
                error_msg = f"处理错误: {str(e)}"
                client_socket.sendall(encrypt(error_msg, key, iv))
                log_callback(f"处理错误: {error_msg}")

    except Exception as e:
        log_callback(f"客户端处理错误: {str(e)}")
    finally:
        client_socket.close()


def start_server(system, ip, port, log_callback, stop_event):
    try:
        server_socket = socket.socket()
        server_socket.bind((ip, port))
        server_socket.listen(5)

        _, actual_port = server_socket.getsockname()
        log_callback(f"服务启动于 {ip}:{actual_port}")

        # 设置超时以便检查停止事件
        server_socket.settimeout(1)

        while not stop_event.is_set():
            try:
                client, addr = server_socket.accept()
                log_callback(f"客户端连接: {addr}")

                # 为每个客户端创建新线程
                client_thread = threading.Thread(
                    target=handle_client,
                    args=(client, system, log_callback),
                    daemon=True
                )
                client_thread.start()

            except socket.timeout:
                # 超时，检查是否要停止
                continue
            except Exception as e:
                # 检查是否因关闭套接字而导致的错误
                if stop_event.is_set():
                    log_callback("服务器正常关闭")
                    break
                else:
                    log_callback(f"服务器错误: {str(e)}")
                    break

    except Exception as e:
        log_callback(f"服务器启动失败: {str(e)}")
    finally:
        server_socket.close()
        log_callback("服务器已停止")


class VotingSystemGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("投票系统服务器")
        self.root.geometry("1000x700")
        self.root.resizable(True, True)

        # 设置应用图标
        try:
            self.root.iconbitmap("server_icon.ico")
        except:
            pass

        # 初始化投票系统
        self.system = VotingSystem()
        self.server_thread = None
        self.stop_event = threading.Event()

        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 创建标签页
        self.notebook = ttk.Notebook(self.main_frame)
        self.notebook.pack(fill=tk.BOTH, expand=True, pady=5)

        # 轮次管理标签页
        self.round_tab = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.round_tab, text="投票轮次管理")

        # 创建轮次部分
        self.create_frame = ttk.LabelFrame(self.round_tab, text="创建新轮次", padding="10")
        self.create_frame.pack(fill=tk.X, pady=5)

        # 轮次名称
        ttk.Label(self.create_frame, text="轮次名称:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.round_name_entry = ttk.Entry(self.create_frame, width=30)
        self.round_name_entry.grid(row=0, column=1, padx=5, pady=5)

        # 投票模式
        ttk.Label(self.create_frame, text="投票模式:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
        self.vote_mode_var = tk.StringVar()
        self.vote_mode_combobox = ttk.Combobox(self.create_frame, textvariable=self.vote_mode_var,
                                               values=["最大", "固定"], width=8)
        self.vote_mode_combobox.grid(row=0, column=3, padx=5, pady=5)
        self.vote_mode_combobox.current(0)

        # 投票数
        ttk.Label(self.create_frame, text="投票数:").grid(row=0, column=4, padx=5, pady=5, sticky=tk.W)
        self.vote_num_entry = ttk.Entry(self.create_frame, width=8)
        self.vote_num_entry.grid(row=0, column=5, padx=5, pady=5)
        self.vote_num_entry.insert(0, "1")

        # 投票类型
        ttk.Label(self.create_frame, text="投票类型:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.vote_type_var = tk.StringVar()
        self.vote_type_combobox = ttk.Combobox(self.create_frame, textvariable=self.vote_type_var,
                                               values=["记名", "无记名"], width=8)
        self.vote_type_combobox.grid(row=1, column=1, padx=5, pady=5)
        self.vote_type_combobox.current(0)

        # 查看密码
        ttk.Label(self.create_frame, text="查看密码:").grid(row=1, column=2, padx=5, pady=5, sticky=tk.W)
        self.password_entry = ttk.Entry(self.create_frame, width=20, show="*")
        self.password_entry.grid(row=1, column=3, padx=5, pady=5)

        # 创建轮次按钮
        self.create_btn = ttk.Button(self.create_frame, text="创建轮次", command=self.create_round)
        self.create_btn.grid(row=1, column=4, padx=10, pady=5)

        # 候选人管理部分
        self.candidate_frame = ttk.LabelFrame(self.round_tab, text="候选人管理", padding="10")
        self.candidate_frame.pack(fill=tk.X, pady=5)

        ttk.Label(self.candidate_frame, text="候选人姓名:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.candidate_name_entry = ttk.Entry(self.candidate_frame, width=30)
        self.candidate_name_entry.grid(row=0, column=1, padx=5, pady=5)

        self.add_candidate_btn = ttk.Button(self.candidate_frame, text="添加候选人",
                                            command=self.add_candidate, state=tk.DISABLED)
        self.add_candidate_btn.grid(row=0, column=2, padx=10, pady=5)

        # 候选人列表
        self.candidate_list_frame = ttk.LabelFrame(self.round_tab, text="候选人列表", padding="10")
        self.candidate_list_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        columns = ("ID", "姓名")
        self.candidate_tree = ttk.Treeview(self.candidate_list_frame, columns=columns, show="headings")
        self.candidate_tree.heading("ID", text="ID")
        self.candidate_tree.heading("姓名", text="姓名")
        self.candidate_tree.column("ID", width=100, anchor=tk.CENTER)
        self.candidate_tree.column("姓名", width=300)

        self.candidate_scroll = ttk.Scrollbar(self.candidate_list_frame, orient=tk.VERTICAL,
                                              command=self.candidate_tree.yview)
        self.candidate_tree.configure(yscroll=self.candidate_scroll.set)

        self.candidate_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.candidate_scroll.pack(side=tk.RIGHT, fill=tk.Y)

        # 服务器管理标签页
        self.server_tab = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.server_tab, text="服务器管理")

        self.server_frame = ttk.LabelFrame(self.server_tab, text="服务器设置", padding="10")
        self.server_frame.pack(fill=tk.X, pady=5)

        ttk.Label(self.server_frame, text="监听IP:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.listen_ip_entry = ttk.Entry(self.server_frame, width=20)
        self.listen_ip_entry.grid(row=0, column=1, padx=5, pady=5)
        self.listen_ip_entry.insert(0, "0.0.0.0")

        ttk.Label(self.server_frame, text="端口:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
        self.listen_port_entry = ttk.Entry(self.server_frame, width=10)
        self.listen_port_entry.grid(row=0, column=3, padx=5, pady=5)
        self.listen_port_entry.insert(0, "9999")

        self.start_btn = ttk.Button(self.server_frame, text="启动服务器", command=self.start_server)
        self.start_btn.grid(row=0, column=4, padx=10, pady=5)

        self.stop_btn = ttk.Button(self.server_frame, text="停止服务器", command=self.stop_server, state=tk.DISABLED)
        self.stop_btn.grid(row=0, column=5, padx=10, pady=5)

        # 服务器状态
        self.status_frame = ttk.LabelFrame(self.server_tab, text="服务器日志", padding="10")
        self.status_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.status_text = scrolledtext.ScrolledText(self.status_frame, wrap=tk.WORD, height=15)
        self.status_text.pack(fill=tk.BOTH, expand=True)
        self.status_text.config(state=tk.DISABLED)

        # 结果管理标签页
        self.result_tab = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.result_tab, text="投票结果管理")

        # 轮次选择
        self.result_select_frame = ttk.LabelFrame(self.result_tab, text="选择轮次", padding="10")
        self.result_select_frame.pack(fill=tk.X, pady=5)

        ttk.Label(self.result_select_frame, text="选择轮次:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.round_var = tk.StringVar()
        self.round_combobox = ttk.Combobox(self.result_select_frame, textvariable=self.round_var, width=30)
        self.round_combobox.grid(row=0, column=1, padx=5, pady=5)

        self.view_result_btn = ttk.Button(self.result_select_frame, text="查看结果", command=self.view_result)
        self.view_result_btn.grid(row=0, column=2, padx=10, pady=5)

        self.save_result_btn = ttk.Button(self.result_select_frame, text="保存结果", command=self.save_result)
        self.save_result_btn.grid(row=0, column=3, padx=10, pady=5)

        self.view_details_btn = ttk.Button(self.result_select_frame, text="查看详情", command=self.view_details)
        self.view_details_btn.grid(row=0, column=4, padx=10, pady=5)

        # 结果显示
        self.result_frame = ttk.LabelFrame(self.result_tab, text="投票结果", padding="10")
        self.result_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.result_text = scrolledtext.ScrolledText(self.result_frame, wrap=tk.WORD)
        self.result_text.pack(fill=tk.BOTH, expand=True)
        self.result_text.config(state=tk.DISABLED)

        # 状态栏
        self.status_bar = ttk.Label(root, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # 设置样式
        self.style = ttk.Style()
        self.style.configure("TButton", padding=6)
        self.style.configure("TLabel", padding=5)
        self.style.configure("TLabelframe.Label", font=('Arial', 10, 'bold'))
        self.style.configure("Treeview", font=('Arial', 9))
        self.style.configure("Treeview.Heading", font=('Arial', 10, 'bold'))

        # 绑定事件
        self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_changed)

        # 日志函数
        self.log_callback = self.log_message
        self.server_socket = None

    def log_message(self, message):
        """记录消息到日志区域"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        full_message = f"[{timestamp}] {message}"

        self.status_text.config(state=tk.NORMAL)
        self.status_text.insert(tk.END, full_message + "\n")
        self.status_text.see(tk.END)  # 滚动到最新消息
        self.status_text.config(state=tk.DISABLED)

        # 更新状态栏
        self.status_bar.config(text=message)

    def on_tab_changed(self, event):
        """标签页切换事件处理"""
        # 当切换到结果管理标签页时，更新轮次列表
        if self.notebook.index(self.notebook.select()) == 2:  # 结果管理标签页索引
            self.update_round_combobox()

    def create_round(self):
        """创建新的投票轮次"""
        name = self.round_name_entry.get().strip()
        if not name:
            messagebox.showwarning("输入错误", "轮次名称不能为空")
            return

        vote_mode = self.vote_mode_var.get()
        if not vote_mode:
            messagebox.showwarning("输入错误", "请选择投票模式")
            return

        try:
            mode_value = int(self.vote_num_entry.get().strip())
        except ValueError:
            messagebox.showwarning("输入错误", "投票数必须是整数")
            return

        vote_type = self.vote_type_var.get()
        if not vote_type:
            messagebox.showwarning("输入错误", "请选择投票类型")
            return

        password = self.password_entry.get().strip()
        if vote_type == '记名' and not password:
            if messagebox.askyesno("密码确认", "记名投票需要密码才能查看详情，是否继续不设置密码？"):
                password = None
            else:
                return

        try:
            round_id = self.system.create_round(name, vote_mode, mode_value, vote_type, password)
            self.add_candidate_btn.config(state=tk.NORMAL)

            # 清空候选人列表
            for item in self.candidate_tree.get_children():
                self.candidate_tree.delete(item)

            self.log_message(f"投票轮次 '{name}' 创建成功! ID: {round_id}")
            messagebox.showinfo("成功", f"轮次#{round_id}创建成功!")

            # 清空输入框
            self.round_name_entry.delete(0, tk.END)
            self.vote_num_entry.delete(0, tk.END)
            self.vote_num_entry.insert(0, "1")
            self.password_entry.delete(0, tk.END)

        except Exception as e:
            messagebox.showerror("错误", f"创建轮次失败: {str(e)}")
            self.log_message(f"创建轮次错误: {str(e)}")

    def add_candidate(self):
        """向当前轮次添加候选人"""
        name = self.candidate_name_entry.get().strip()
        if not name:
            messagebox.showwarning("输入错误", "候选人姓名不能为空")
            return

        current_round = self.system.get_current_round()
        if not current_round:
            messagebox.showwarning("错误", "没有活动轮次")
            return

        try:
            cid = current_round.add_candidate(name)
            self.candidate_tree.insert("", "end", values=(cid, name))
            self.log_message(f"候选人 '{name}' 已添加，ID: {cid}")
            self.status_bar.config(text=f"候选人 '{name}' 已添加，ID: {cid}")
            self.candidate_name_entry.delete(0, tk.END)
        except Exception as e:
            messagebox.showerror("错误", f"添加候选人失败: {str(e)}")
            self.log_message(f"添加候选人错误: {str(e)}")

    def start_server(self):
        """启动投票服务器"""
        if not self.system.rounds:
            messagebox.showwarning("错误", "请先创建至少一个投票轮次")
            return

        ip = self.listen_ip_entry.get().strip() or "0.0.0.0"
        try:
            port = int(self.listen_port_entry.get().strip() or 9999)
        except ValueError:
            messagebox.showwarning("输入错误", "端口必须是整数")
            return

        # 检查端口是否在合法范围
        if port < 0 or port > 65535:
            messagebox.showwarning("输入错误", "端口号必须在0-65535之间")
            return

        try:
            # 设置停止事件
            self.stop_event.clear()

            # 创建服务器线程
            self.server_thread = threading.Thread(
                target=start_server,
                args=(self.system, ip, port, self.log_callback, self.stop_event),
                daemon=True
            )
            self.server_thread.start()

            # 更新UI状态
            self.start_btn.config(state=tk.DISABLED)
            self.stop_btn.config(state=tk.NORMAL)
            self.status_bar.config(text="服务器正在运行")

        except Exception as e:
            messagebox.showerror("服务器错误", f"无法启动服务器: {str(e)}")
            self.log_message(f"启动服务器失败: {str(e)}")

    def stop_server(self):
        """停止投票服务器"""
        try:
            self.stop_event.set()
            self.log_message("正在停止服务器...")

            # 创建临时套接字连接到服务器以解除accept()阻塞
            try:
                temp_socket = socket.socket()
                temp_socket.connect(("127.0.0.1", int(self.listen_port_entry.get().strip() or 9999)))
                temp_socket.close()
            except:
                pass

            # 等待服务器线程结束
            if self.server_thread and self.server_thread.is_alive():
                self.server_thread.join(timeout=3.0)

            # 更新UI状态
            self.start_btn.config(state=tk.NORMAL)
            self.stop_btn.config(state=tk.DISABLED)
            self.log_message("服务器已停止")
            self.status_bar.config(text="服务器已停止")

        except Exception as e:
            messagebox.showerror("错误", f"停止服务器失败: {str(e)}")
            self.log_message(f"停止服务器错误: {str(e)}")

    def update_round_combobox(self):
        """更新轮次下拉框"""
        values = []
        for rid, rnd in self.system.rounds.items():
            status = "活动" if rnd.status == "active" else "已结束"
            values.append(f"{rid}: {rnd.name} ({status})")
        self.round_combobox["values"] = values
        if values:
            self.round_combobox.current(0)

    def get_selected_round_id(self):
        """获取选择的轮次ID"""
        selected = self.round_combobox.get()
        if not selected:
            messagebox.showwarning("选择错误", "请先选择轮次")
            return None

        try:
            # 提取轮次ID（格式：ID: 名称）
            return int(selected.split(":")[0])
        except:
            messagebox.showwarning("选择错误", "无效的轮次选择")
            return None

    def view_result(self):
        """查看投票结果"""
        round_id = self.get_selected_round_id()
        if round_id is None:
            return

        rnd = self.system.rounds.get(round_id)
        if not rnd:
            messagebox.showwarning("错误", "轮次不存在")
            return

        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)

        # 显示投票结果摘要
        self.result_text.insert(tk.END, rnd.get_summary())
        self.log_message(f"查看轮次 {round_id} 的投票结果")
        self.status_bar.config(text=f"显示轮次 {round_id} 的投票结果")

        self.result_text.config(state=tk.DISABLED)

    def view_details(self):
        """查看投票详情（仅记名投票）"""
        round_id = self.get_selected_round_id()
        if round_id is None:
            return

        rnd = self.system.rounds.get(round_id)
        if not rnd:
            messagebox.showwarning("错误", "轮次不存在")
            return

        if rnd.vote_type != '记名':
            messagebox.showinfo("提示", "无记名投票，无法查看详情")
            return

        password = simpledialog.askstring("密码验证", "请输入查看密码:", show="*")
        if not password:
            return

        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)

        # 显示投票详情
        details = rnd.get_voter_info(password)
        self.result_text.insert(tk.END, details)
        self.log_message(f"查看轮次 {round_id} 的投票详情")
        self.status_bar.config(text=f"显示轮次 {round_id} 的投票详情")

        self.result_text.config(state=tk.DISABLED)

    def save_result(self):
        """保存投票结果"""
        round_id = self.get_selected_round_id()
        if round_id is None:
            return

        rnd = self.system.rounds.get(round_id)
        if not rnd:
            messagebox.showwarning("错误", "轮次不存在")
            return

        if rnd.vote_type == '记名':
            password = simpledialog.askstring("密码验证", "请输入查看密码:", show="*")
            if not password:
                return
            result = rnd.save_voter_info(password)
        else:
            result = rnd.save_to_file()

        messagebox.showinfo("保存结果", result)
        self.log_message(f"保存轮次 {round_id} 的结果: {result}")
        self.status_bar.config(text=f"保存轮次 {round_id} 的结果")

    def on_closing(self):
        """关闭窗口时的处理"""
        # 停止服务器
        if self.stop_btn["state"] == tk.NORMAL:
            self.stop_server()

        # 自动结束所有活动轮次
        for rid, rnd in self.system.rounds.items():
            if rnd.status == "active":
                self.log_message(f"自动结束轮次 {rid}")
                rnd.status = "closed"
                self.log_message(rnd.save_to_file())

        self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = VotingSystemGUI(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()

